package com.changgou.seckill.timer;

import com.changgou.seckill.dao.SeckillGoodsMapper;
import com.changgou.seckill.pojo.SeckillGoods;
import entity.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author 秦川熙
 * 定时任务方法配置， 定时将秒杀商品存入到Redis缓存
 */
@Component
public class SeckillGoodsPushTask {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 定时任内方法
     * 0/30 * * * * ?：从每分钟的第0秒开始执行， 没过30秒执行一次
     * 1、查询符合当前参与秒杀的时间菜单
     * 2、秒杀商品库存 -> 0 stock_count
     * 3、审核状态 -> 审核通过  status:1
     * 4、开始时间   start_time, 结束时间 end_time
     *  时间菜单的开始时间<=start_time && end_time<时间菜单的开始时间+2小时
     *  时间： 时间菜单
     *  ①求出整个时间菜单
     *  ②确定每个事件菜单的区间值   14-16
     *  ③根据菜单时间的区间值对应的秒杀商品数据
     *  ④将对应的时间区间的秒杀商品数据存入到Redis
     */
    @Scheduled(cron = "0/30 * * * * ?")
    public void loadGoodsPushRedis() {
        //获取时间段集合
        List<Date> dateMenus = DateUtil.getDateMenus();
        //循环时间段
        for (Date startTime : dateMenus) {
            //namespace = SeckillGoods_startTime
            //时间的字符串格式 yyyyMMddHH
            String extName = DateUtil.date2Str(startTime, DateUtil.PATTERN_YYYYMMDDHH);

            //根据时间段数据查询对应的秒杀商品数据
            Example example = new Example(SeckillGoods.class);
            Example.Criteria criteria = example.createCriteria();

            //1、商品必须审核通过  status=1
            criteria.andEqualTo("status", "1");
            //2、库存>0
            criteria.andGreaterThan("stockCount", 0);
            //3、开始时间 <= 活动开始时间
            criteria.andGreaterThanOrEqualTo("startTime", startTime);
            //4、活动结束时间 < 开始时间+2小时
            criteria.andLessThan("endTime", DateUtil.addDateHour(startTime, 2));
            //5、排除之前已经加载到Redis缓存中的商品数据
            Set keys = redisTemplate.boundHashOps("SeckillGoods_" + extName).keys();
            if (keys != null && keys.size() > 0) {
                criteria.andNotIn("id", keys);
            }

            //查询数据
            List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectByExample(example);

            //将商品数据存入到Redis缓存
            for (SeckillGoods seckillGood : seckillGoods) {
                redisTemplate.boundHashOps("SeckillGoods_" + extName).put(seckillGood.getId(), seckillGood);
                //设置有效时期
                redisTemplate.expireAt("SeckillGoods_" + extName, DateUtil.addDateHour(startTime, 2));
                //商品数据队列存储， 防止高并发超卖
                Long[] ids = pushIds(seckillGood.getStockCount(), seckillGood.getId());
                redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillGood.getId()).leftPushAll(ids);
                //自增计数器
                //自增计数器
                redisTemplate.boundHashOps("SeckillGoodsCount").increment(seckillGood.getId(), seckillGood.getStockCount());
            }
        }
    }

    /**
     * 将商品id存入到数组中
     * @param len：长度
     * @param id：值
     * @return
     */
    public Long[] pushIds(int len, Long id) {
        Long[] ids = new Long[len];
        for (int i = 0; i < ids.length; i++) {
            ids[i] = id;
        }
        return ids;
    }

}
